package com.tool.sqlexecutor.command;

import com.tool.sqlexecutor.config.Config;
import com.tool.sqlexecutor.config.ConfigCache;
import com.tool.sqlexecutor.config.DataSourceProperty;
import com.tool.sqlexecutor.sql.MultiDataSourceExecutor;
import com.tool.sqlexecutor.sql.MultiDataSourceQuery;
import com.tool.sqlexecutor.sql.SqlExecutor;
import com.tool.sqlexecutor.util.SqlResourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.shell.standard.ShellOption;
import org.springframework.shell.standard.ValueProviderSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@ShellComponent
public class SqlCommands {
    Logger logger = LoggerFactory.getLogger(SqlCommands.class);

    @ShellMethod("执行指定脚本,可以指定脚本文件,也可以指定sql,如果指定sql则忽略脚本文件")
    public String run(@ShellOption(value = {"--env", "-e"}, help = "指定执行环境,比如 DEV;也可以使用[;,/]等符号指定多个环境") String env,
                      @ShellOption(value = {"--index", "-i"}, defaultValue = "-1", help = "配合env使用,用来指定特定数据库实例") int index,
                      @ShellOption(value = {"--sql", "-s"}, defaultValue = "", help = "待执行的SQL语句") String sql,
                      @ShellOption(value = {"--script", "--file", "-f"}, defaultValue = "", help = "待执行的脚本文件") File script,
                      @ShellOption(value = "--separator", defaultValue = "", help = "指定切分SQL的字符，默认;") String separator) throws InterruptedException {

        if (ConfigCache.INSTANCE.getConfig() == null) {
            return "Please update the configuration first.Reference reset [file]";
        }
        if (StringUtils.isEmpty(sql) && StringUtils.isEmpty(script.getName())) {
            return "Please specify SQL statement or SQL script";
        }

        logger.info("env - " + env);
        List<DataSourceProperty> dataSourceProperties = Arrays.stream(env.split("[;,/]")).flatMap(e -> loadDataSourceConfig(e, index).stream()).collect(Collectors.toList());
        //List<DataSourceProperty> dataSourceProperties = loadDataSourceConfig(env, index);
        if (CollectionUtils.isEmpty(dataSourceProperties)) {
            return "Not loaded into configuration information!";
        }
        if (!StringUtils.isEmpty(sql)) {
            logger.info("sql:" + sql);
            return new MultiDataSourceExecutor(dataSourceProperties, SqlResourceBuilder.getResource(sql), separator).run();
        } else if (!StringUtils.isEmpty(script.getName())) {
            logger.info("script:" + script.getAbsolutePath());
            return new MultiDataSourceExecutor(dataSourceProperties, SqlResourceBuilder.getResource(script), separator).run();
        }

        return "No SQL is executed!";
    }

    private List<DataSourceProperty> loadDataSourceConfig(String env, int index) {
        Config config = ConfigCache.INSTANCE.getConfig();
        if (!config.getServer().containsKey(env)) {
            logger.error("env:" + env + " error!");
            return new ArrayList<>(0);
        }

        List<DataSourceProperty> dataSourceProperties = config.getServer().get(env);
        if (index >= 0 && index < dataSourceProperties.size()) {
            return dataSourceProperties.subList(index, index + 1);
        }
        return dataSourceProperties;
    }

    @ShellMethod("执行查询语句")
    public String query(@ShellOption(value = {"--env", "-e"}, help = "指定执行环境,比如 DEV;也可以使用[;,/]等符号指定多个环境") String env,
                        @ShellOption(value = {"--index", "-i"}, defaultValue = "-1", help = "配合env使用,用来指定特定数据库实例") int index,
                        @ShellOption(value = {"--sql", "-s"}, defaultValue = "", help = "待执行的SQL语句,例如:\"select 1 from dual;\"") String sql) {
        if (ConfigCache.INSTANCE.getConfig() == null) {
            return "Please update the configuration first.";
        }
        if (StringUtils.isEmpty(sql)) {
            return "Please specify SQL statement";
        }

        logger.info("env - " + env);
        List<DataSourceProperty> dataSourceProperties = Arrays.stream(env.split("[;,/]")).flatMap(e -> loadDataSourceConfig(e, index).stream()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(dataSourceProperties)) {
            return "Not loaded into configuration information!";
        }

        return new MultiDataSourceQuery(dataSourceProperties, sql).query();
    }
}
